package cn.zyq.ykb.system.pay.core.client.impl.wx;

import cn.hutool.core.io.IoUtil;
import cn.zyq.ykb.system.config.weixin.WxAppProperties;
import cn.zyq.ykb.system.config.weixin.WxMaProperties;
import cn.zyq.ykb.system.config.weixin.WxMpProperties;
import cn.zyq.ykb.system.exception.BusinessException;
import cn.zyq.ykb.system.pay.config.PayWxProperties;
import cn.zyq.ykb.system.pay.core.client.PayClient;
import cn.zyq.ykb.system.pay.core.client.PayClientConfig;
import cn.zyq.ykb.system.pay.core.client.impl.PayClientFactoryImpl;
import cn.zyq.ykb.system.pay.core.enums.PayChannelEnum;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotBlank;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Set;

/**
 * 微信支付的 PayClientConfig 实现类
 * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性
 *
 * @author 芋道源码
 */
@Slf4j
@Data
public class WXPayClientConfig implements PayClientConfig {

    /**
     * API 版本 - V2
     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1
     */
    public static final String API_VERSION_V2 = "v2";
    /**
     * API 版本 - V3
     * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml
     */
    public static final String API_VERSION_V3 = "v3";

    /**
     * 公众号或者小程序的 appid
     */
    @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class})
    private String appId;
    /**
     * 商户号
     */
    @NotBlank(message = "商户号 不能为空", groups = {V2.class, V3.class})
    private String mchId;
    /**
     * API 版本
     */
    @NotBlank(message = "API 版本 不能为空", groups = {V2.class, V3.class})
    private String apiVersion;

    // ========== V2 版本的参数 ==========

    /**
     * 商户密钥
     */
    @NotBlank(message = "商户密钥 不能为空", groups = V2.class)
    private String mchKey;
    /**
     * apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径.
     * 对应的字符串
     *
     * 注意，可通过 {@link #main(String[])} 读取
     */
    /// private String keyContent;

    // ========== V3 版本的参数 ==========
    /**
     * apiclient_key.pem 证书文件的绝对路径或者以 classpath: 开头的类路径.
     * 对应的字符串
     * 注意，可通过 {@link #main(String[])} 读取
     */
    @NotBlank(message = "apiclient_key 不能为空", groups = V3.class)
    private String privateKeyContent;
    /**
     * apiclient_cert.pem 证书文件的绝对路径或者以 classpath: 开头的类路径.
     * 对应的字符串
     * <p>
     * 注意，可通过 {@link #main(String[])} 读取
     */
    @NotBlank(message = "apiclient_cert 不能为空", groups = V3.class)
    private String privateCertContent;
    /**
     * apiV3 密钥值
     */
    @NotBlank(message = "apiV3 密钥值 不能为空", groups = V3.class)
    private String apiV3Key;

    /**
     * 分组校验 v2版本
     */
    public interface V2 {
    }

    /**
     * 分组校验 v3版本
     */
    public interface V3 {
    }

    @Override
    public Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator) {
        return validator.validate(this, this.getApiVersion().equals(API_VERSION_V2) ? V2.class : V3.class);
    }

    public static PayClient getPayClientByChannelId(Integer channelId) {
        if (PayChannelEnum.WX_H5.getChannelId().equals(channelId)) {
            return getH5PayClient();
        } else if (PayChannelEnum.WX_LITE.getChannelId().equals(channelId)) {
            return getLitePayClient();
        } else if (PayChannelEnum.WX_APP.getChannelId().equals(channelId)) {
            return getAppPayClient();
        } else if (PayChannelEnum.WX_PUB.getChannelId().equals(channelId)) {
            return getPubPayClient();
        } else {
            throw new BusinessException("没有获取到准确的渠道");
        }
    }

    public static PayClient getH5PayClient() {
        WXPayClientConfig config = new WXPayClientConfig();
        PayClient client = null;
        try {
            config.setAppId(WxMpProperties.appId);
            config.setMchId(PayWxProperties.mchId);
            config.setApiVersion(WXPayClientConfig.API_VERSION_V2);
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_key.pem")));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_cert.pem")));
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateKeyContent)));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateCertContent)));
            // config.setApiV3Key(PayWxProperties.apiV3Key);
            config.setMchKey(PayWxProperties.apiV2Key);
            // 创建客户端
            Integer channelId = PayChannelEnum.WX_H5.getChannelId();
            PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
            payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_H5.getCode(), config);
            client = payClientFactory.getPayClient(channelId);
        } catch (Exception e) {
            log.error("获取支付客户端失败");
            log.error(e.getMessage(), e);
        }
        return client;
    }

    /**
     * 获取微信app支付端
     *
     * @return
     */
    public static PayClient getAppPayClient() {
        WXPayClientConfig config = new WXPayClientConfig();
        PayClient client = null;
        try {
            config.setAppId(WxAppProperties.appId);
            config.setMchId(PayWxProperties.mchId);
            config.setApiVersion(WXPayClientConfig.API_VERSION_V2);
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_key.pem")));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_cert.pem")));
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateKeyContent)));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateCertContent)));
            config.setMchKey(PayWxProperties.apiV2Key);
            // 创建客户端
            Integer channelId = PayChannelEnum.WX_APP.getChannelId();
            PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
            payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_APP.getCode(), config);
            client = payClientFactory.getPayClient(channelId);
        } catch (Exception e) {
            log.error("获取支付客户端失败");
            log.error(e.getMessage(), e);
        }
        return client;
    }


    /**
     * 获取微信小程序支付端
     *
     * @return
     */
    public static PayClient getLitePayClient() {
        WXPayClientConfig config = new WXPayClientConfig();
        PayClient client = null;
        try {
            config.setAppId(WxMaProperties.appId);
            config.setMchId(PayWxProperties.mchId);
            config.setApiVersion(WXPayClientConfig.API_VERSION_V2);
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_key.pem")));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_cert.pem")));
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateKeyContent)));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateCertContent)));
            // config.setApiV3Key(PayWxProperties.apiV3Key);
            config.setMchKey(PayWxProperties.apiV2Key);
            // 创建客户端
            Integer channelId = PayChannelEnum.WX_LITE.getChannelId();
            PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
            payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_LITE.getCode(), config);
            client = payClientFactory.getPayClient(channelId);
        } catch (Exception e) {
            log.error("获取支付客户端失败");
            log.error(e.getMessage(), e);
        }
        return client;
    }

    /**
     * 获取微信 JSAPI 支付支付端
     *
     * @return
     */
    public static PayClient getPubPayClient() {
        WXPayClientConfig config = new WXPayClientConfig();
        PayClient client = null;
        try {
            config.setAppId(WxMpProperties.appId);
            config.setMchId(PayWxProperties.mchId);
            config.setApiVersion(WXPayClientConfig.API_VERSION_V2);
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_key.pem")));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("D:\\WxCertUtil\\cert\\1628797751_20220720_cert/apiclient_cert.pem")));
            // config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateKeyContent)));
            // config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream(PayWxProperties.privateCertContent)));
            // config.setApiV3Key(PayWxProperties.apiV3Key);
            config.setMchKey(PayWxProperties.apiV2Key);
            // 创建客户端
            Integer channelId = PayChannelEnum.WX_PUB.getChannelId();
            PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
            payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_PUB.getCode(), config);
            client = payClientFactory.getPayClient(channelId);
        } catch (Exception e) {
            log.error("获取支付客户端失败");
            log.error(e.getMessage(), e);
        }
        return client;
    }

    public static void main(String[] args) throws FileNotFoundException {
        String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.p12";
        /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_key.pem";
        /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.pem";
        System.out.println(IoUtil.readUtf8(new FileInputStream(path)));
    }

}
